#pragma warning(disable:4786) // to disable warning c4786, g++ 8.4 no warning
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

/*
reference link : 
http://www.cplusplus.com/reference/vector/
http://www.cplusplus.com/reference/vector/vector/
https://blog.csdn.net/pengshengli/article/details/86287794

Define:

Member types:

Member functions
Iterators:
begin
    Return iterator to beginning (public member function )

end
    Return iterator to end (public member function )

rbegin
    Return reverse iterator to reverse beginning (public member function )

rend
    Return reverse iterator to reverse end (public member function )

cbegin
    Return const_iterator to beginning (public member function )

cend
    Return const_iterator to end (public member function )

crbegin
    Return const_reverse_iterator to reverse beginning (public member function )

crend
    Return const_reverse_iterator to reverse end (public member function )
Capacity:
size:
    Return size (public member function )
    http://www.cplusplus.com/reference/vector/vector/size/
max_size
    Return maximum size (public member function )

resize
    Change size (public member function )

capacity
    Return size of allocated storage capacity (public member function )

empty
    Test whether vector is empty (public member function )

reserve
    Request a change in capacity (public member function )

shrink_to_fit
    Shrink to fit (public member function )
Element access:
operator[]
    Access element (public member function )

at
    Access element (public member function )

front
    Access first element (public member function )

back
    Access last element (public member function )

data
    Access data (public member function )
Modifiers:
assign
    Assign vector content (public member function )

push_back
    Add element at the end (public member function )

pop_back
    Delete last element (public member function )

insert
    Insert elements (public member function )

erase
    Erase elements (public member function )

swap
    Swap content (public member function )

clear
    Clear content (public member function )

emplace
    Construct and insert element (public member function )

emplace_back
    Construct and insert element at the end (public member function )
Allocator:
get_allocator
    Get allocator (public member function )
Non-member function overloads:
relational operators
    Relational operators for vector (function template )

swap
    Exchange contents of vectors (function template )
Template specializations:
vector<bool>
    Vector of bool (class template specialization )
*/
using namespace std;
int StrVec()
{
    vector<string>mysvt; // define class template objects my string vectors
    mysvt.reserve(4);
    mysvt.push_back("1. Beijing City.");
    mysvt.push_back("2. Tianjin City.");
    mysvt.push_back("3. Shanghai City.");
    mysvt.push_back("4. Chongqing City.");
    cout << "OK!" << endl;
    vector<string>::iterator it;
    for(it=mysvt.begin(); it != mysvt.end(); it++)
        cout << *it << endl;
    int m = mysvt.size();
    int n = mysvt.capacity();
    int m1= mysvt.max_size();
    cout <<"vector:mysvt, size is "     << m  << endl;
    cout <<"vector:mysvt, capacity is " << n  << endl;
    cout <<"vector:mysvt, maxsize is "  << m1 << endl;
    mysvt.resize(10);
    cout << "resize mysvt to 10";
    int n1 = mysvt.capacity();
    int n2 = mysvt.size();
    cout <<"vector:mysvt, capacity is " << n1  << endl;
    cout <<"vector:mysvt, size is "     << n2  << endl;

    for(it=mysvt.begin(); it != mysvt.end(); it++) 
    {
        if(*it=="")
            cout << "******" << endl;
        cout << *it << endl;
    }  
    
    //cin.get();
    return 0;
}

struct ST {
    int id;
    double db;
};

void Origin(int num, vector<ST>& vt)
{
    int m = num;
    ST temp;
    for(int i = 0; i < m; i++)
    {
        temp.id = i + 1;
        temp.db = (i+1)*10;
        vt.push_back(temp);
    }
}



void Iter_for(vector<ST> & vt)
{
    ST temp;
    vector<ST>::iterator iter;
    for(iter=vt.begin(); iter!=vt.end(); iter++)
    {
        temp = *iter;
        cout << "id: " << temp.id << ", db:  " << temp.db << endl;
    }
}

void at_for(vector<ST> & vt)
{
    ST temp;
    int i = 0;
    int m = vt.size();
    for(i = 0; i < m; i++)
    {
        temp = vt.at(i);
        cout << "id: " << temp.id << ", db:  " << temp.db << endl;

    }
}

int useOrign()
{
    
    ST tmp;
    vector<ST> myvt;
    Origin(5,myvt);
    int size = myvt.size();
    cout << "size: " << size << endl;

    cout << "Iterator output!" << endl;
    Iter_for(myvt);
    cout << "at() output!" << endl;
    at_for(myvt);
    cout << "empty() usage:" << endl;
    while(!myvt.empty())
    {
        tmp = myvt.back();
        cout << "id " << tmp.id << ", db: " << tmp.db << endl;
        myvt.pop_back();
    }
    return 0; 
}

struct Student{
    int id;
    double score;
};

template <class T> void Original(T & myvt){
    Student temp;
    temp.id=1;
    temp.score=90;
    myvt.push_back(temp);
    temp.id=2;
    temp.score=95;
    myvt.push_back(temp);
    temp.id=3;
    temp.score=98;
    myvt.push_back(temp);
    temp.id=4;
    temp.score=97;
    myvt.push_back(temp);
    temp.id=5;
    temp.score=95;
    myvt.push_back(temp);
    temp.id=6;
    temp.score=90;
    myvt.push_back(temp);
}

void out(Student & stu)
{
    cout << "id: " << stu.id <<", score: " << stu.score << endl;
}

bool greater95(Student & stu)
{
    if((stu.score) >= 95.0)
        return 1;
    else
        return 0;
}

void useAlgo()
{
    vector<Student> myvt;
    vector<Student>::iterator iter;
    int countV=0;
    Original(myvt);
    for_each(myvt.begin(), myvt.end(), out);
    countV=count_if(myvt.begin(), myvt.end(), greater95);
    cout << "The Number of the elements > 95.0: " << countV << endl;
}

void use_size()
{
    std::vector<int> myints;
    std::cout << "0. size: " << myints.size() << '\n';

    for (int i=0; i<10; i++) myints.push_back(i);
    std::cout << "1. size: " << myints.size() << '\n';

    myints.insert (myints.end(),10,100);
    std::cout << "2. size: " << myints.size() << '\n';

    myints.pop_back();
    std::cout << "3. size: " << myints.size() << '\n';
}

void use_swap()
{
    std::vector<int> foo (3,100);   // three ints with a value of 100
    std::vector<int> bar (5,200);   // five ints with a value of 200

    foo.swap(bar);

    std::cout << "foo contains:";
    for (unsigned i=0; i<foo.size(); i++)
        std::cout << ' ' << foo[i];
    std::cout << '\n';

    std::cout << "bar contains:";
    for (unsigned i=0; i<bar.size(); i++)
        std::cout << ' ' << bar[i];
    std::cout << '\n';
}

void use_at()
{
    //http://www.cplusplus.com/reference/vector/vector/at/
    std::vector<int> myvector (10);   // 10 zero-initialized ints

    // assign some values:
    for (unsigned i=0; i<myvector.size(); i++)
        myvector.at(i)=i;

    std::cout << "myvector contains:";
    for (unsigned i=0; i<myvector.size(); i++)
        std::cout << ' ' << myvector.at(i);
    std::cout << '\n';
}

void use_assign()
{
    //http://www.cplusplus.com/reference/vector/vector/assign/
    std::vector<int> first;
    std::vector<int> second;
    std::vector<int> third;

    first.assign (7,100);             // 7 ints with a value of 100

    std::vector<int>::iterator it;
    it=first.begin()+1;

    second.assign (it,first.end()-1); // the 5 central values of first

    int myints[] = {1776,7,4};
    third.assign (myints,myints+3);   // assigning from array.

    std::cout << "Size of first: " << int (first.size()) << '\n';
    std::cout << "Size of second: " << int (second.size()) << '\n';
    std::cout << "Size of third: " << int (third.size()) << '\n';
}

void use_data()
{
    //http://www.cplusplus.com/reference/vector/vector/data/
    std::vector<int> myvector (5);

    int* p = myvector.data();

    *p = 10;
    ++p;
    *p = 20;
    p[2] = 100;

    std::cout << "myvector contains:";
    for (unsigned i=0; i<myvector.size(); ++i)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';
}

void diff_begin_cbegin()
{
    //begin
    std::vector<int> myvector1;
    for (int i=1; i<=5; i++) myvector1.push_back(i);

    std::cout << "myvector1 contains:";
    for (std::vector<int>::iterator it = myvector1.begin() ; it != myvector1.end(); ++it)
        std::cout << ' ' << *it;
    std::cout << '\n';
    //cbegin
    std::vector<int> myvector2 = {10,20,30,40,50};

    std::cout << "myvector2 contains:";

    for (auto it = myvector2.cbegin(); it != myvector2.cend(); ++it)
    std::cout << ' ' << *it;
    std::cout << '\n';
    /*
        in my mind, the difference is auto, cbegin will create iterator automatically
    */
}

void use_reserve()
{
    // in my mind, reserve will set the mininum capacity
    std::vector<int>::size_type sz;

    std::vector<int> foo;
    sz = foo.capacity();
    std::cout << "making foo grow:\n";
    for (int i=0; i<100; ++i) {
        foo.push_back(i);
        if (sz!=foo.capacity()) {
            sz = foo.capacity();
            std::cout << "capacity changed: " << sz << '\n';
        }
    }

    std::vector<int> bar;
    sz = bar.capacity();
    bar.reserve(100);   // this is the only difference with foo above
    std::cout << "making bar grow:\n";
    for (int i=0; i<100; ++i) {
        bar.push_back(i);
        if (sz!=bar.capacity()) {
            sz = bar.capacity();
            std::cout << "capacity changed: " << sz << '\n';
        }
    }
}

void use_resize()
{
    std::vector<int> myvector;

    // set some initial content:
    for (int i=1;i<10;i++) myvector.push_back(i);

    myvector.resize(5);
    myvector.resize(8,100);
    myvector.resize(12);

    std::cout << "myvector contains:";
    for (int i=0;i<myvector.size();i++)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';
}

void about_size()
{
    std::vector<int> myvector;

    std::cout << "size: " << (int) myvector.size() << '\n';
    std::cout << "capacity: " << (int) myvector.capacity() << '\n';
    std::cout << "max_size: " << (int) myvector.max_size() << '\n';

    // set some content in the vector:
    for (int i=0; i<2; i++) myvector.push_back(i);

    std::cout << "size: " << (int) myvector.size() << '\n';
    std::cout << "capacity: " << (int) myvector.capacity() << '\n';
    std::cout << "max_size: " << (int) myvector.max_size() << '\n';

    myvector.reserve(200);
    std::cout << "size: " << (int) myvector.size() << '\n';
    std::cout << "capacity: " << (int) myvector.capacity() << '\n';
    std::cout << "max_size: " << (unsigned int) myvector.max_size() << '\n';
    // I think capacity can be changed itself 
    // if no reserving
    // if size = 1, capacity = 1
    // if size = 2, capacity = 2
    // if size = 3,4, capacity = 4
    // if size = 5,6,7,8, capacity = 8
    // ...
}

void use_insert()
{
    std::vector<int> myvector (3,100);
    std::vector<int>::iterator it;

    it = myvector.begin();
    it = myvector.insert ( it , 200 );

    myvector.insert (it,2,300);

    // "it" no longer valid, get a new one:
    it = myvector.begin();

    std::vector<int> anothervector (2,400);
    myvector.insert (it+2,anothervector.begin(),anothervector.end());

    int myarray [] = { 501,502,503 };
    myvector.insert (myvector.begin(), myarray, myarray+3);

    std::cout << "myvector contains:";
    for (it=myvector.begin(); it<myvector.end(); it++)
        std::cout << ' ' << *it;
    std::cout << '\n';
}

void use_erase()
{
    std::vector<int> myvector;

    // set some values (from 1 to 10)
    for (int i=1; i<=10; i++) myvector.push_back(i);

    // erase the 6th element
    myvector.erase (myvector.begin()+5);

    // erase the first 3 elements:
    myvector.erase (myvector.begin(),myvector.begin()+3);

    std::cout << "myvector contains:";
    for (unsigned i=0; i<myvector.size(); ++i)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';
}

void use_front()
{
    std::vector<int> myvector;

    myvector.push_back(78);
    myvector.push_back(16);

    // now front equals 78, and back 16

    myvector.front() -= myvector.back();

    std::cout << "myvector.front() is now " << myvector.front() << '\n';
}

void use_back()
{
    std::vector<int> myvector;

    myvector.push_back(10);

    while (myvector.back() != 0)
    {
        myvector.push_back ( myvector.back() -1 );
    }

    std::cout << "myvector contains:";
    for (unsigned i=0; i<myvector.size() ; i++)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';
}

void use_clear()
{
    std::vector<int> myvector;
    myvector.push_back (100);
    myvector.push_back (200);
    myvector.push_back (300);

    std::cout << "myvector contains:";
    for (unsigned i=0; i<myvector.size(); i++)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';

    myvector.clear();
    myvector.push_back (1101);
    myvector.push_back (2202);

    std::cout << "myvector contains:";
    for (unsigned i=0; i<myvector.size(); i++)
        std::cout << ' ' << myvector[i];
    std::cout << '\n';
}

int main()
{
    StrVec();
    useOrign();
    useAlgo();

    use_size();
    use_swap();
    use_at();
    use_assign();
    use_data();
    diff_begin_cbegin();
    use_reserve();
    use_resize();
    about_size();
    use_insert();
    use_erase();
    use_front();
    use_back();
    use_clear();

    return 0;
}